package edu.hawaii.senin.iclouds.basics;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;

/**
 * No bury container for species population. It provides iterator over the species.
 *
 * @author Pavel Senin.
 *
 */
public class PopulationSimple implements AbstractPopulation {

  /**
   * Internal active species storage.
   */
  private TreeMap<String, Specie> storage;

  /**
   * Creates new empty Population.
   *
   */
  public PopulationSimple() {
    this.storage = new TreeMap<String, Specie>();
  }

  /**
   * Creates new Population by using provided map.
   *
   * @param accretionSample species to put into the population.
   */
  public PopulationSimple(TreeMap<String, Specie> accretionSample) {

    this.storage = accretionSample;
  }

  /** {@inheritDoc} */
  public String addProduct(String specieName, Long amount) {
    StringBuffer res = new StringBuffer(200);

    if (this.storage.containsKey(specieName)) {
      res.append("adding " + specieName);
      this.storage.get(specieName).incrementAccumulatorValue(amount);
    }
    else if (specieName.length() > 1) {
      res.append("creating " + specieName + " molecule bin in storage");
      this.storage.put(specieName, new Molecule(specieName, amount));
    }
    else {
      res.append("creating " + specieName + " atom bin in storage");
      this.storage.put(specieName, new Atom(specieName, amount));
    }

    return res.toString();
  }

  /** {@inheritDoc} */
  public void addSpecie(String spName, Specie sp, Long amnt) throws PopulationException {
    if (this.storage.containsKey(spName)) {
      throw new PopulationException("population already contains the " + spName);
    }
    else {
      sp.setAccumulatorValue(amnt);
      this.storage.put(spName, sp);
    }
  }

  /** {@inheritDoc} */
  public boolean contains(String specieName) {
    return this.storage.containsKey(specieName);
  }

  /** {@inheritDoc} */
  public void decrementSpecieAccumulator(String specieName, Long value) throws PopulationException {
    if (this.storage.containsKey(specieName)) {
      Specie sp = this.storage.get(specieName);
      sp.decrementAccumulatorValue(value);
      if (sp.getAccumulatorValue() <= 0) {
        this.storage.remove(sp.getName());
      }
    }
    else {
      throw new PopulationException("specie " + specieName
          + "not found in the population while decrementing.");
    }
  }

  /** {@inheritDoc} */
  public Specie getSpecie(String specieName) {
    if (this.storage.containsKey(specieName)) {
      return this.storage.get(specieName);
    }
    return null;
  }

  /**
   * Generates text message that used to log the Chemistry process.
   *
   * @return the message.
   */
  public StringBuffer getLogMessage() {
    StringBuffer reply = new StringBuffer(500);
    for (Specie sp : this.storage.values()) {
      reply.append(sp.getName() + " " + sp.getAccumulatorValue() + " ");
    }
    return (reply);
  }

  /**
   * Reports all the species names.
   *
   * @return the species names within the population.
   */
  public Set<String> getSpeciesNames() {
    return this.storage.keySet();
  }

  /** {@inheritDoc} */
  public Long getPopulationTotalSize() {
    Long res = 0L;
    for (Specie sp : this.storage.values()) {
      res += sp.getAccumulatorValue().longValue();
    }
    return res;
  }

  /** {@inheritDoc} */
  public void incrementSpecieAccumulator(String specieName, Long incrementValue)
      throws PopulationException {
    if (this.storage.containsKey(specieName)) {
      Specie sp = this.storage.get(specieName);
      sp.incrementAccumulatorValue(incrementValue);
    }
    else {
      throw new PopulationException("specie " + specieName
          + "not found in the population while incrementing");
    }
  }

  /** {@inheritDoc} */
  public Iterator<Specie> iterator() {
    return this.storage.values().iterator();
  }

  /** {@inheritDoc} */
  public void removeSpecie(String specieName) {
    if (this.storage.containsKey(specieName)) {
      this.storage.remove(specieName);
    }
  }

  /** {@inheritDoc} */
  public Integer getPopulationSpeciesNum() {
    return this.storage.size();
  }

  /** {@inheritDoc} */
  public Long getSpecieVolume(String specieName) throws PopulationException {
    if (this.storage.containsKey(specieName)) {
      return this.storage.get(specieName).getAccumulatorValue();
    }
    else {
      throw new PopulationException("specie " + specieName
          + "not found in the population while incrementing");
    }
  }
}
